﻿using System;
using System.Collections.Generic;
using System.Text;

namespace IOP.OpenType
{
    /// <summary>
    /// CFF表操作符
    /// </summary>
    public class CFFOperator
    {
        private readonly byte B0;
        private readonly byte B1;
        /// <summary>
        /// 操作符Id
        /// </summary>
        public int OperatorId { get { return (B1 << 8) | B0; } }
        /// <summary>
        /// 操作符名称
        /// </summary>
        public string Name { get; }
        /// <summary>
        /// 
        /// </summary>
        public OperatorKind OperatorKind { get; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="b0"></param>
        /// <param name="b1"></param>
        /// <param name="name"></param>
        /// <param name="operand"></param>
        public CFFOperator(byte b0, byte b1, string name, OperatorKind operand)
        {
            B0 = b0; B1 = b1;
            Name = name;
            OperatorKind = operand;
        }

        /// <summary>
        /// CFF表操作符字典
        /// </summary>
        public static Dictionary<int, CFFOperator> OperatorDictionary { get; } = new Dictionary<int, CFFOperator>();
        /// <summary>
        /// 获取操作符
        /// </summary>
        /// <param name="b0"></param>
        /// <param name="b1"></param>
        /// <returns></returns>
        public static CFFOperator GetOperator(byte b0, byte b1) => OperatorDictionary[(b1 << 8) | b0];
        /// <summary>
        /// 尝试获取操作符
        /// </summary>
        /// <param name="b0"></param>
        /// <param name="b1"></param>
        /// <param name="operator"></param>
        /// <returns></returns>
        public static bool TryGetOperator(byte b0, byte b1, out CFFOperator @operator) => OperatorDictionary.TryGetValue((b1 << 8) | b0, out @operator);
        /// <summary>
        /// 静态构造函数
        /// </summary>
        static CFFOperator()
        {
            //Table 9: Top DICT Operator Entries          
            Register(0, 0, "version", OperatorKind.SID);
            Register(1, 0, "Notice", OperatorKind.SID);
            Register(12, 0, "Copyright", OperatorKind.SID);
            Register(2, 0, "FullName", OperatorKind.SID);
            Register(3, 0, "FamilyName", OperatorKind.SID);
            Register(4, 0, "Weight", OperatorKind.SID);
            Register(12, 1, "isFixedPitch", OperatorKind.Boolean);
            Register(12, 2, "ItalicAngle", OperatorKind.Number);
            Register(12, 3, "UnderlinePosition", OperatorKind.Number);
            Register(12, 4, "UnderlineThickness", OperatorKind.Number);
            Register(12, 5, "PaintType", OperatorKind.Number);
            Register(12, 6, "CharstringType", OperatorKind.Number);
            Register(12, 7, "FontMatrix", OperatorKind.Array);
            Register(13, 0, "UniqueID", OperatorKind.Number);
            Register(5, 0, "FontBBox", OperatorKind.Array);
            Register(12, 8, "StrokeWidth", OperatorKind.Number);
            Register(14, 0, "XUID", OperatorKind.Array);
            Register(15, 0, "charset", OperatorKind.Number);
            Register(16, 0, "Encoding", OperatorKind.Number);
            Register(17, 0, "CharStrings", OperatorKind.Number);
            Register(18, 0, "Private", OperatorKind.NumberNumber);
            Register(12, 20, "SyntheticBase", OperatorKind.Number);
            Register(12, 21, "PostScript", OperatorKind.SID);
            Register(12, 22, "BaseFontName", OperatorKind.SID);
            Register(12, 23, "BaseFontBlend", OperatorKind.SID);

            //Table 10: CIDFont Operator Extensions
            Register(12, 30, "ROS", OperatorKind.SIDSIDNumber);
            Register(12, 31, "CIDFontVersion", OperatorKind.Number);
            Register(12, 32, "CIDFontRevision", OperatorKind.Number);
            Register(12, 33, "CIDFontType", OperatorKind.Number);
            Register(12, 34, "CIDCount", OperatorKind.Number);
            Register(12, 35, "UIDBase", OperatorKind.Number);
            Register(12, 36, "FDArray", OperatorKind.Number);
            Register(12, 37, "FDSelect", OperatorKind.Number);
            Register(12, 38, "FontName", OperatorKind.SID);

            //Table 23: Private DICT Operators
            Register(6, 0, "BlueValues", OperatorKind.Delta);
            Register(7, 0, "OtherBlues", OperatorKind.Delta);
            Register(8, 0, "FamilyBlues", OperatorKind.Delta);
            Register(9, 0, "FamilyOtherBlues", OperatorKind.Delta);
            Register(12, 9, "BlueScale", OperatorKind.Number);
            Register(12, 10, "BlueShift", OperatorKind.Number);
            Register(12, 11, "BlueFuzz", OperatorKind.Number);
            Register(10, 0, "StdHW", OperatorKind.Number);
            Register(11, 0, "StdVW", OperatorKind.Number);
            Register(12, 12, "StemSnapH", OperatorKind.Delta);
            Register(12, 13, "StemSnapV", OperatorKind.Delta);
            Register(12, 14, "ForceBold", OperatorKind.Boolean);

            Register(12, 17, "LanguageGroup", OperatorKind.Number);
            Register(12, 18, "ExpansionFactor", OperatorKind.Number);
            Register(12, 19, "initialRandomSeed", OperatorKind.Number);

            Register(19, 0, "Subrs", OperatorKind.Number);
            Register(20, 0, "defaultWidthX", OperatorKind.Number);
            Register(21, 0, "nominalWidthX", OperatorKind.Number);
        }
        /// <summary>
        /// 注册CFF表操作符
        /// </summary>
        /// <param name="b0"></param>
        /// <param name="b1"></param>
        /// <param name="name"></param>
        /// <param name="operand"></param>
        static void Register(byte b0, byte b1, string name, OperatorKind operand)
        {
            OperatorDictionary.Add((b1 << 8) | b0, new CFFOperator(b0, b1, name, operand));
        }
    }

    /// <summary>
    /// 操作符类型
    /// </summary>
    public enum OperatorKind
    {
        /// <summary>
        /// SID
        /// </summary>
        SID,
        /// <summary>
        /// 布尔值
        /// </summary>
        Boolean,
        /// <summary>
        /// 数值
        /// </summary>
        Number,
        /// <summary>
        /// 数组
        /// </summary>
        Array,
        /// <summary>
        /// 差值
        /// </summary>
        Delta,
        NumberNumber,
        SIDSIDNumber,
    }
}
